//
//  Test.m
//  Test
//
//  Created by yuan xiaodong on 2021/12/22.
//  Copyright © 2021 yuan. All rights reserved.
//

#import <XCTest/XCTest.h>
#import <AVFoundation/AVFoundation.h>
#import "ListNode.h"
#import "BinaryTree.h"

@interface Test : XCTestCase

@end

@implementation Test

- (void)setUp {
    // Put setup code here. This method is called before the invocation of each test method in the class.
}

- (void)tearDown {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
}

- (void)testAlgorithm{
    
}

static int sum = 0; // 全排列个数

// 递归实现数组全排列
// prefixIndex - 表示前缀的位置
// number - 要排列的数目
- (void)permutation:(NSMutableArray *)arrayM prefixIndex:(int)prefixIndex number:(int)number {
    if (prefixIndex == number - 1) { // 前缀是最后一个位置,此时打印排列数
        // 打印数组结果
        sum += 1;
        [self print:arrayM len:number index:sum];
    } else {
        for (int i = prefixIndex; i < number; i++) {
            // 交换前缀,使之产生下一个前缀. i 递增,所以可以保证数组中的每一个元素都位于第0个,作为前缀的起始字符
            [self swap:arrayM i:prefixIndex j:i];

            // 以递归的方式对剩下的元素进行全排列
            [self permutation:arrayM prefixIndex:prefixIndex + 1 number:number];
            
            // 将前缀换回来,继续做上一个的前缀排列.
            [self swap:arrayM i:prefixIndex j:i];
        }
    }
}

// 实现两数交换
- (void)swap:(NSMutableArray *)arrM i:(NSUInteger)i j:(NSUInteger)j {
    NSNumber *temp = arrM[i];
    arrM[i] = arrM[j];
    arrM[j] = temp;
}

// 打印数组内容
- (void)print:(NSMutableArray *)arrM len:(NSUInteger)len index:(int)index {
    NSMutableString *strM = [NSMutableString string];
    for (NSUInteger i = 0; i < len; i++) {
        [strM appendString:[NSString stringWithFormat:@"%@ ",arrM[i]]];
    }
    NSLog(@"index:[%d] %@",index,strM);
}

#pragma mark - *********** 线程相关 ***********

- (void)testThread{
    NSLog(@"A");
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"B");
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"C");
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"D");
                //死锁，当前主线程，再同步主线程
                dispatch_sync(dispatch_get_main_queue(), ^{
                    NSLog(@"E");
                });
            });
        });

        dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"F");
            //死锁，当前主线程，再同步主线程
            dispatch_sync(dispatch_get_main_queue(), ^{
                NSLog(@"G");
            });
        });
    });
    NSLog(@"I");
}

#pragma mark - *********** 国际化相关 ***********

//表情国家代码校验
- (void)testEmojiCheck {
    //读取原有的plist信息
    NSString *plistPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"emoji" ofType:@"plist"];
    NSMutableDictionary *plistDic = [[NSDictionary dictionaryWithContentsOfFile:plistPath] mutableCopy];
    NSMutableArray *iconArr = [[plistDic valueForKey:@"icons"] mutableCopy];
    NSMutableArray *iconNewArr = @[].mutableCopy;
    
    //读取新的json信息
    NSString *jsonPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"emoji_ru" ofType:@"json"];
    
    NSError *error;
    NSData *jsonData = [[NSData alloc] initWithContentsOfFile:jsonPath];
    NSMutableArray *jsonArr = [[NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error] mutableCopy];
    
    for (NSDictionary *iconDic in iconArr){
        
        NSMutableDictionary *iconNewDic = [iconDic mutableCopy];
        NSString *code = iconDic[@"code"];
        
        NSMutableDictionary *nameDic = @{}.mutableCopy;
        
        for (NSDictionary *iconDic2 in jsonArr){
            NSString *code2 = iconDic2[@"id"];
            
            if ([code isEqualToString:code2]){
                NSString *zh = [iconDic2 valueForKey:@"zh"];
                zh = [zh stringByReplacingOccurrencesOfString:@"[" withString:@""];
                zh = [zh stringByReplacingOccurrencesOfString:@"]" withString:@""];
                
                NSString *en = [iconDic2 valueForKey:@"en"];
                en = [en stringByReplacingOccurrencesOfString:@"[" withString:@""];
                en = [en stringByReplacingOccurrencesOfString:@"]" withString:@""];
                
                NSString *fr = [iconDic2 valueForKey:@"fr"];
                fr = [fr stringByReplacingOccurrencesOfString:@"[" withString:@""];
                fr = [fr stringByReplacingOccurrencesOfString:@"]" withString:@""];
                
                NSString *pt = [iconDic2 valueForKey:@"pt"];
                pt = [pt stringByReplacingOccurrencesOfString:@"[" withString:@""];
                pt = [pt stringByReplacingOccurrencesOfString:@"]" withString:@""];
                
                NSString *es = [iconDic2 valueForKey:@"es"];
                es = [es stringByReplacingOccurrencesOfString:@"[" withString:@""];
                es = [es stringByReplacingOccurrencesOfString:@"]" withString:@""];
                
                NSString *ru = [iconDic2 valueForKey:@"ru"];
                ru = [ru stringByReplacingOccurrencesOfString:@"[" withString:@""];
                ru = [ru stringByReplacingOccurrencesOfString:@"]" withString:@""];
                
                [nameDic setValue:zh forKey:@"zh"];
                [nameDic setValue:en forKey:@"en"];
                [nameDic setValue:fr forKey:@"fr"];
                [nameDic setValue:pt forKey:@"pt"];
                [nameDic setValue:es forKey:@"es"];
                [nameDic setValue:ru forKey:@"ru"];
            }
            
        }
        //通过code和国家标识，去更新或插入
        
        [iconNewDic setValue:nameDic forKey:@"name"];
        [iconNewArr addObject:iconNewDic];
    }
    
    [plistDic setValue:iconNewArr forKey:@"icons"];
    NSLog(@"%@",plistDic);
    
    
    NSString *savePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    savePath = [NSString stringWithFormat:@"%@/new.plist",savePath];
    
    [plistDic writeToFile:savePath atomically:YES];
//    NSData *data = [NSJSONSerialization dataWithJSONObject:plistDic options:NSJSONWritingPrettyPrinted error:nil];
//
//    BOOL res = [[NSFileManager defaultManager] createFileAtPath:savePath contents:data attributes:nil];
//
    NSLog(@"%@",savePath);
     
}

- (void)testEmojiCheck2 {
    //读取原有的plist信息
    NSString *plistPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"emoji" ofType:@"plist"];
    NSMutableDictionary *plistDic = [[NSDictionary dictionaryWithContentsOfFile:plistPath] mutableCopy];
    NSMutableArray *iconArr = [[plistDic valueForKey:@"icons"] mutableCopy];
    NSMutableArray *iconNewArr = @[].mutableCopy;
    
    //读取新的json信息
    NSString *jsonPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"es_ES" ofType:@"json"];
    
    NSError *error;
    NSData *jsonData = [[NSData alloc] initWithContentsOfFile:jsonPath];
    NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
    
    for (NSDictionary *iconDic in iconArr){
        
        NSMutableDictionary *iconNewDic = [iconDic mutableCopy];
        NSString *code = iconDic[@"code"];
        
        NSMutableDictionary *newNameDic = [iconDic[@"name"] mutableCopy];
        
        for (NSString *jsonKey in [jsonDic allKeys]){
            
            if ([jsonKey isEqualToString:code]){
                NSString *es = [NSString stringWithFormat:@"%@",jsonDic[code]];
                es = [es stringByReplacingOccurrencesOfString:@"[" withString:@""];
                es = [es stringByReplacingOccurrencesOfString:@"]" withString:@""];
                
                NSLog(@"key:%@ es：%@",jsonKey,es);
                [newNameDic setObject:es forKey:@"es"];
            }
        }
        
        //通过code和国家标识，去更新或插入
        
        [iconNewDic setValue:newNameDic forKey:@"name"];
        [iconNewArr addObject:iconNewDic];
    }
    
    [plistDic setValue:iconNewArr forKey:@"icons"];
    NSLog(@"%@",plistDic);
    
    
    NSString *savePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    savePath = [NSString stringWithFormat:@"%@/new.plist",savePath];
    
    [plistDic writeToFile:savePath atomically:YES];
//    NSData *data = [NSJSONSerialization dataWithJSONObject:plistDic options:NSJSONWritingPrettyPrinted error:nil];
//
//    BOOL res = [[NSFileManager defaultManager] createFileAtPath:savePath contents:data attributes:nil];
//
    NSLog(@"%@",savePath);
     
}

- (void)testCompressVideo{
    NSString *originalPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"IMG_0429" ofType:@"MOV"];
    NSURL *originalUrl = [NSURL fileURLWithPath:originalPath];
    
    NSString *savePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    savePath = [NSString stringWithFormat:@"%@/video.MP4",savePath];
    NSURL *saveUrl = [NSURL fileURLWithPath:savePath];
    
    [self compressVideo:originalUrl outputUrl:saveUrl withVideoSettings:[self videoCompressSettings] AudioSettings:[self audioCompressSettings] fileType:AVFileTypeMPEG4 complete:^(NSURL * _Nullable url, NSError * _Nullable error) {
        NSLog(@"%@",url);
    }];
    
    NSLog(@"%@",originalUrl);
}

- (void)testPerformanceExample {
    // This is an example of a performance test case.
    [self measureBlock:^{
        // Put the code you want to measure the time of here.
    }];
}

//视频压缩
- (void)compressVideo:(NSURL *)videoUrl
            outputUrl:(NSURL *)outputUrl
    withVideoSettings:(NSDictionary *)videoSettings
        AudioSettings:(NSDictionary *)audioSettings
             fileType:(AVFileType)fileType
             complete:(void (^)(NSURL * _Nullable, NSError * _Nullable))complete {
  
  AVAsset *asset = [AVAsset assetWithURL:videoUrl];
  AVAssetReader *reader = [AVAssetReader assetReaderWithAsset:asset error:nil];
  AVAssetWriter *writer = [AVAssetWriter assetWriterWithURL:outputUrl fileType:fileType error:nil];
  
  // video part
  AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
  AVAssetReaderTrackOutput *videoOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoTrack outputSettings:[self videoOutputSettings]];
  AVAssetWriterInput *videoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
  if ([reader canAddOutput:videoOutput]) {
    [reader addOutput:videoOutput];
  }
  if ([writer canAddInput:videoInput]) {
    [writer addInput:videoInput];
  }
  
  // audio part
  AVAssetTrack *audioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] firstObject];
  AVAssetReaderTrackOutput *audioOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings:[self audioOutputSettings]];
  AVAssetWriterInput *audioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:audioSettings];
  if ([reader canAddOutput:audioOutput]) {
    [reader addOutput:audioOutput];
  }
  if ([writer canAddInput:audioInput]) {
    [writer addInput:audioInput];
  }
  
  // 开始读写
  [reader startReading];
  [writer startWriting];
  [writer startSessionAtSourceTime:kCMTimeZero];
  
  //创建视频写入队列
  dispatch_queue_t videoQueue = dispatch_queue_create("Video Queue", DISPATCH_QUEUE_SERIAL);
  //创建音频写入队列
  dispatch_queue_t audioQueue = dispatch_queue_create("Audio Queue", DISPATCH_QUEUE_SERIAL);
  //创建一个线程组
  dispatch_group_t group = dispatch_group_create();
  //进入线程组
  dispatch_group_enter(group);
    
    [videoInput requestMediaDataWhenReadyOnQueue:videoQueue usingBlock:^{
        while ([videoInput isReadyForMoreMediaData]) {
            CMSampleBufferRef sampleBuffer;
            if ([reader status] == AVAssetReaderStatusReading && (sampleBuffer = [videoOutput copyNextSampleBuffer])){
                BOOL result = [videoInput appendSampleBuffer:sampleBuffer];
                CFRelease(sampleBuffer);
                if (!result){
                    [reader cancelReading];
                    break;
                }
            }else{
                [videoInput markAsFinished];
                dispatch_group_leave(group);
            }
        }
    }];
    
  
  dispatch_group_enter(group);
  //队列准备好后 usingBlock
  [audioInput requestMediaDataWhenReadyOnQueue:audioQueue usingBlock:^{
    while ([audioInput isReadyForMoreMediaData]) {
        CMSampleBufferRef sampleBuffer;
        if ([reader status] == AVAssetReaderStatusReading && (sampleBuffer = [audioOutput copyNextSampleBuffer])){
            BOOL result = [audioInput appendSampleBuffer:sampleBuffer];
            CFRelease(sampleBuffer);
            if (!result){
                [reader cancelReading];
                break;
            }
        }else{
            [audioInput markAsFinished];
            dispatch_group_leave(group);
        }
    }
  }];
  
  //完成压缩
  dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    if ([reader status] == AVAssetReaderStatusReading) {
      [reader cancelReading];
    }
    
    switch (writer.status) {
      case AVAssetWriterStatusWriting: {
          NSLog(@"视频压缩完成");
        [writer finishWritingWithCompletionHandler:^{
          
          // 可以尝试异步回至主线程回调
          if (complete) {
            complete(outputUrl,nil);
          }
          
        }];
      }
        break;
          
      case AVAssetWriterStatusCancelled:
            NSLog(@"取消压缩");
        break;
          
      case AVAssetWriterStatusFailed:
            NSLog(@"===error：%@===", writer.error);
        if (complete) {
          complete(nil,writer.error);
        }
        break;
          
      case AVAssetWriterStatusCompleted: {
          NSLog(@"视频压缩完成");
        [writer finishWritingWithCompletionHandler:^{
          
          // 可以尝试异步回至主线程回调
          if (complete) {
            complete(outputUrl,nil);
          }
        }];
      }
        break;
          
      default:
        break;
    }
  });
}

/** 视频解码 */
- (NSDictionary *)videoOutputSettings {

  NSDictionary *videoOutputSetting = @{
    (__bridge NSString *)kCVPixelBufferPixelFormatTypeKey:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_422YpCbCr8],
    (__bridge NSString *)kCVPixelBufferIOSurfacePropertiesKey:[NSDictionary dictionary]
  };
    
  return videoOutputSetting;
}

/** 音频解码 */
- (NSDictionary *)audioOutputSettings {
  NSDictionary *audioOutputSetting = @{
    AVFormatIDKey: @(kAudioFormatLinearPCM)
  };
  return audioOutputSetting;
}

/// 指定音视频的压缩码率，profile，帧率等关键参数信息
- (NSDictionary *)videoCompressSettings {
  NSDictionary *compressionProperties = @{
    AVVideoAverageBitRateKey          : @(409600), // 码率 400K
    AVVideoExpectedSourceFrameRateKey : @30, // 帧率
    AVVideoProfileLevelKey            : AVVideoProfileLevelH264HighAutoLevel
  };
  
  NSString *videoCodeec;
  if (@available(iOS 11.0, *)) {
      videoCodeec = AVVideoCodecTypeH264;
  } else {
      videoCodeec = AVVideoCodecH264;
  }
  NSDictionary *videoCompressSettings = @{
    AVVideoCodecKey                 : videoCodeec,
    AVVideoWidthKey                 : @960,
    AVVideoHeightKey                : @540,
    AVVideoCompressionPropertiesKey : compressionProperties,
    AVVideoScalingModeKey           : AVVideoScalingModeResizeAspectFill
  };
  
  return videoCompressSettings;
}

- (NSDictionary *)audioCompressSettings {
  AudioChannelLayout stereoChannelLayout = {
    .mChannelLayoutTag = kAudioChannelLayoutTag_Stereo,
    .mChannelBitmap = 0,
    .mNumberChannelDescriptions = 0
  };
  NSData *channelLayoutAsData = [NSData dataWithBytes:&stereoChannelLayout length:offsetof(AudioChannelLayout, mChannelDescriptions)];
  NSDictionary *audioCompressSettings = @{
    AVFormatIDKey         : @(kAudioFormatMPEG4AAC),
    AVEncoderBitRateKey   : @(49152), // 码率 48K
    AVSampleRateKey       : @44100, // 采样率
    AVChannelLayoutKey    : channelLayoutAsData,
    AVNumberOfChannelsKey : @(2)  // 声道
  };
  
  return audioCompressSettings;
}

@end
